Daily trade alerts for BTC, ETH and XMR

Mark Ziemann https://mdz-analytics.com

2022-09-29

unlink("banner.png")

file.copy("../images/banner1.png", "banner.png")

banner

Source code

Intro

In the backtesting analysis, I have established these profitable strategies for timing entry/exits. Click on the hyperlinks below to see how these signals were identified.

  • Simple and exponential moving averages for BTC, ETH and XMR.

  • Moving average crosses for BTC, ETH and XMR.

  • Directional movement index (DMI) for BTC, ETH and XMR.

  • True strength index (TSI) for BTC, ETH and XMR.

  • Stochastic oscillator (stoch) for BTC, ETH and XMR.

  • Double RSI and BTC, ETH and XMR.

  • Donchian channel BTC, ETH and XMR.

  • Know Sure Thing (KST) indicator BTC, ETH and XMR.

  • Ensemble indicator BTC, ETH and XMR.

This script will examine the price action and these trade signals just before the daily close. If the signal is TRUE, it is bullish and if FALSE it is bearish. When there is a switch from bearish to bullish it is a buy signal and when it switches from bullish to bearish it is a sell signal. This HTML is updated just before the daily close each day, but push notifications for any trade signals are also sent by push bullet.

To receive these signals in real-time, subscribe to the following channels - it’s free for a limited time!

https://www.pushbullet.com/channel?tag=btc_signal

https://www.pushbullet.com/channel?tag=eth_signal

https://www.pushbullet.com/channel?tag=xmr_signal

If you need some help to design your own trading signals/strategies, I am happy to help for a fee. email me at for any enquiries/suggestions/feedback.

This report is distributed for FREE under the MIT licence, but if you find it useful, consider a small tip.

Monero Address

Reminder: this analysis is not financial advice.

suppressPackageStartupMessages({
  library("jsonlite")
  library("tidyverse")
  library("runner")
  library("quantmod")
  library("TTR")
  library("kableExtra")
})

TESTING = FALSE
system("DATE=$(date -u) ; sed \"s/MYTIME/${DATE}/\" ../index0.html > ../index1.html")

mydate <- Sys.time()
attr(mydate, "tzone") <- "UTC"
mydate <- as.Date(mydate)

BTC

Get price data

Obtaining BTC price data (daily) for the last 300 days.

Bitcoin is the oldest and largest cryptocurrency.

URL="https://web-api.coinmarketcap.com/v1/cryptocurrency/ohlcv/historical?symbol=BTC&convert=USD&interval=daily&count=300"
download.file(URL,destfile="btcdat.txt")
btcdat <- fromJSON("btcdat.txt")
price <- btcdat$data$quotes
price <- data.frame(  as.Date(price$time_close) , price$quote$USD$high, price$quote$USD$low, price$quote$USD$close)
colnames(price) <- c("date","high","low","close")

URL="https://web-api.coinmarketcap.com/v1/cryptocurrency/ohlcv/historical?symbol=BTC&convert=USD&interval=hourly&time_period=hourly&count=11"
download.file(URL,destfile="btcdat.txt")
btcdat <- fromJSON("btcdat.txt")
price2 <- btcdat$data$quotes
price2 <- data.frame( as.Date(price2$time_close) , price2$quote$USD$high, price2$quote$USD$low, price2$quote$USD$close,stringsAsFactors=FALSE)
colnames(price2) <- c("date","high","low","close")

high <- max(price2[,2])
low <-  min(price2[,3])
close <- price2[nrow(price2),4]

df <- data.frame(date=mydate,high=high,low=low,close=close,stringsAsFactors=FALSE)
price <- rbind(price,df)
tail(price) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close
2022-09-24 19310.20 18861.97 18937.01
2022-09-25 19134.73 18696.47 18802.10
2022-09-26 19274.87 18721.29 19222.67
2022-09-27 20338.46 18915.67 19110.55
2022-09-28 19688.34 18553.30 19426.72
2022-09-29 19574.06 18924.35 19452.39
if ( TESTING == TRUE) {
  price[nrow(price),"close"] <- price[nrow(price),"close"] * 2
}

Now fetch the backtested parameters.

params <- read.table("https://mdz-analytics.com/coins/BTC/BTC_dat.txt", header=TRUE)
params %>% kbl(caption="BTC optimised backtested parameters") %>%  kable_styling("hover", full_width = F)
BTC optimised backtested parameters
indicator parameter meanROI totalROI ntrades ndays xhodl
SMA 44 1.154362 914.2692 83 3404 5.853695
EMA 76 1.224865 633.1203 57 3404 4.053613
SMAcross 44,8 1.383369 1544.3129 37 3404 9.887610
EMAcross 56,26 2.856009 1574.6489 15 3404 10.081839
DMI 128 5.160312 948.1809 12 3404 6.070818
DC 21 1.326361 661.1740 37 3404 4.233229
TSI 100,4,15 1.132427 1261.2834 99 3404 8.075487
stoch 16,54,6 1.132085 729.6873 87 3404 4.671893
RSI2 57,95 1.129494 659.8321 103 3404 4.224638
KST 1.7,0.18,19 1.173615 1301.0709 83 3404 8.330230
Ensemble SMAcross,EMAcross,DMI,TSI,stoch,DC,KST,2 1.611814 2691.2032 51 3404 18.189243

BTC SMA indicator

Now to determine whether BTC has crossed the SMA line.

price2 <- price

n <- as.numeric(params[params$indicator == "SMA",2])

price2$ma <- SMA(Cl(price2),n=n)
price2$signal <- price2$close > price2$ma
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close ma signal
2022-09-24 19310.20 18861.97 18937.01 20814.90 FALSE
2022-09-25 19134.73 18696.47 18802.10 20687.61 FALSE
2022-09-26 19274.87 18721.29 19222.67 20569.40 FALSE
2022-09-27 20338.46 18915.67 19110.55 20451.01 FALSE
2022-09-28 19688.34 18553.30 19426.72 20343.96 FALSE
2022-09-29 19574.06 18924.35 19452.39 20243.26 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    btc_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    btc_signal="SELL"
  }
} else {
btc_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_SMA=TRUE
  system("sed -i 's/BTC_SMA_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/BTC_SMA_COL/limegreen/' ../index1.html")
} else {
  ens_SMA=FALSE
  system("sed -i 's/BTC_SMA_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/BTC_SMA_COL/red/' ../index1.html")
}

message(paste("BTC SMA signal:",btc_signal))
## BTC SMA signal: NONE
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="BTC SMA")
grid()
lines(price2$ma~ as.Date(price2$date) ,col="red")

BTC EMA indicator

Now to determine whether BTC has crossed the EMA line.

price2 <- price

n <- as.numeric(params[params$indicator == "EMA",2])

price2$ma <- EMA(Cl(price2),n=n)
price2$signal <- price2$close > price2$ma
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close ma signal
2022-09-24 19310.20 18861.97 18937.01 21745.76 FALSE
2022-09-25 19134.73 18696.47 18802.10 21669.30 FALSE
2022-09-26 19274.87 18721.29 19222.67 21605.75 FALSE
2022-09-27 20338.46 18915.67 19110.55 21540.94 FALSE
2022-09-28 19688.34 18553.30 19426.72 21486.03 FALSE
2022-09-29 19574.06 18924.35 19452.39 21433.21 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    btc_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    btc_signal="SELL"
  }
} else {
btc_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_EMA=TRUE
  system("sed -i 's/BTC_EMA_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/BTC_EMA_COL/limegreen/' ../index1.html")
} else {
  ens_EMA=FALSE
  system("sed -i 's/BTC_EMA_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/BTC_EMA_COL/red/' ../index1.html")
}

message(paste("BTC EMA signal:",btc_signal))
## BTC EMA signal: NONE
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="BTC EMA")
grid()
lines(price2$ma~ as.Date(price2$date) ,col="red")

BTC SMA cross indicator

The SMA cross is a highly profitable strategy.

price2 <- price

n <- as.numeric(unlist(strsplit(params[params$indicator == "SMAcross",2],",")))
n1 <- n[1]
n2 <- n[2]

price2$ma1 <- SMA(Cl(price2),n=n1)
price2$ma2 <- SMA(Cl(price2),n=n2)

price2$signal <- price2$ma2 > price2$ma1
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close ma1 ma2 signal
2022-09-24 19310.20 18861.97 18937.01 20814.90 19272.20 FALSE
2022-09-25 19134.73 18696.47 18802.10 20687.61 19106.52 FALSE
2022-09-26 19274.87 18721.29 19222.67 20569.40 19081.91 FALSE
2022-09-27 20338.46 18915.67 19110.55 20451.01 19027.71 FALSE
2022-09-28 19688.34 18553.30 19426.72 20343.96 19094.70 FALSE
2022-09-29 19574.06 18924.35 19452.39 20243.26 19207.83 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    btc_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    btc_signal="SELL"
  }
} else {
btc_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_SMAcross=TRUE
  system("sed -i 's/BTC_SMACROSS_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/BTC_SMACROSS_COL/limegreen/' ../index1.html")
} else {
  ens_SMAcross=FALSE
  system("sed -i 's/BTC_SMACROSS_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/BTC_SMACROSS_COL/red/' ../index1.html")
}

message(paste("BTC SMA cross signal is",btc_signal))
## BTC SMA cross signal is NONE
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="BTC SMA cross")
grid()
lines(price2$ma1~ as.Date(price2$date) ,col="red")
lines(price2$ma2~ as.Date(price2$date) ,col="blue")

BTC EMA cross indicator

The EMA cross is a moderately profitable strategy.

price2 <- price

n <- as.numeric(unlist(strsplit(params[params$indicator == "EMAcross",2],",")))
n1 <- n[1]
n2 <- n[2]

price2$ma1 <- EMA(Cl(price2),n=n1)
price2$ma2 <- EMA(Cl(price2),n=n2)

price2$signal <- price2$ma2 > price2$ma1
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close ma1 ma2 signal
2022-09-24 19310.20 18861.97 18937.01 20984.03 20031.22 FALSE
2022-09-25 19134.73 18696.47 18802.10 20907.47 19940.18 FALSE
2022-09-26 19274.87 18721.29 19222.67 20848.36 19887.03 FALSE
2022-09-27 20338.46 18915.67 19110.55 20787.38 19829.51 FALSE
2022-09-28 19688.34 18553.30 19426.72 20739.64 19799.68 FALSE
2022-09-29 19574.06 18924.35 19452.39 20694.47 19773.95 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    btc_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    btc_signal="SELL"
  }
} else {
btc_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_EMAcross=TRUE
  system("sed -i 's/BTC_EMACROSS_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/BTC_EMACROSS_COL/limegreen/' ../index1.html")
} else {
  ens_EMAcross=FALSE
  system("sed -i 's/BTC_EMACROSS_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/BTC_EMACROSS_COL/red/' ../index1.html")
}

message(paste("BTC EMA cross signal is",btc_signal))
## BTC EMA cross signal is NONE
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="BTC EMA cross")
grid()
lines(price2$ma1~ as.Date(price2$date) ,col="red")
lines(price2$ma2~ as.Date(price2$date) ,col="blue")

BTC DMI indicator

Directional movement indicator is a good approach to identify trend changes.

n <- as.numeric(params[params$indicator == "DMI",2])

dmi.adx <- ADX(price[,c("high","low","close")],n=n)
price2 <- cbind(price,dmi.adx)
price2$signal <- dmi.adx[,1] > dmi.adx[,2]
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close DIp DIn DX ADX signal
2022-09-24 19310.20 18861.97 18937.01 18.77333 27.24031 18.40103 17.89867 FALSE
2022-09-25 19134.73 18696.47 18802.10 18.72439 27.26775 18.57569 17.90396 FALSE
2022-09-26 19274.87 18721.29 19222.67 18.74619 27.17755 18.35949 17.90752 FALSE
2022-09-27 20338.46 18915.67 19110.55 19.22200 26.94666 16.73139 17.89833 FALSE
2022-09-28 19688.34 18553.30 19426.72 19.09159 26.98044 17.12286 17.89227 FALSE
2022-09-29 19574.06 18924.35 19452.39 19.01716 26.87525 17.12286 17.88626 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    btc_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    btc_signal="SELL"
  }
} else {
  btc_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_DMI=TRUE
  system("sed -i 's/BTC_DMI_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/BTC_DMI_COL/limegreen/' ../index1.html")
} else {
  ens_DMI=FALSE
  system("sed -i 's/BTC_DMI_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/BTC_DMI_COL/red/' ../index1.html")
}

message(paste("BTC DMI signal:",btc_signal))
## BTC DMI signal: NONE
price2 <- as.data.frame(price2)
par(mfrow=c(2,1))
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="BTC USD price")
grid()
plot(price2$DIp~as.Date(price2$date),type="l", col="blue",
  xlab="Date",ylab="price (USD)",main="BTC DMI")
grid()
lines(price2$DIn ~ as.Date(price2$date) ,col="red")

BTC TSI indicator

Probably the best performing indicator across most price series data.

n <- as.numeric(unlist(strsplit(params[params$indicator == "TSI",2],",")))
n1 <- n[1]
n2 <- n[2]
ns <- n[3]

TSI <- function(x, n.first = 25, n.second = 13, n.signal = 7) {
  #True Strength Indicator
  #https://school.stockcharts.com/doku.php?id=technical_indicators:true_strength_index
  x <- try.xts(x, error = as.matrix)
  pc <- x - lag.xts(x, na.pad = T) #force lag.xts to get na padding
  dspc <- EMA(EMA(pc, n = n.first), n = n.second)
  dsapc <- EMA(EMA(abs(pc), n = n.first), n = n.second)

  tsi <- 100 * (dspc/dsapc)
  signal <- EMA(tsi, n = n.signal)
  r <- cbind(tsi, signal)
  r <- reclass(r, x)
  if (!is.null(dim(r))) colnames(r) <- c("tsi", "signal")
  return(r)
}

tsi <- TSI(price$close , n.first = n1, n.second = n2, n.signal = ns )
colnames(tsi) <- c("tsi","sig")

price2 <- cbind(price,tsi)
price2$signal <- tsi[,1] > tsi[,2]
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close tsi sig signal
2022-09-24 19310.20 18861.97 18937.01 -14.35621 -13.66366 FALSE
2022-09-25 19134.73 18696.47 18802.10 -14.66811 -13.78922 FALSE
2022-09-26 19274.87 18721.29 19222.67 -14.13987 -13.83305 FALSE
2022-09-27 20338.46 18915.67 19110.55 -13.96778 -13.84989 FALSE
2022-09-28 19688.34 18553.30 19426.72 -13.31960 -13.78360 TRUE
2022-09-29 19574.06 18924.35 19452.39 -12.88504 -13.67128 TRUE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    btc_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    btc_signal="SELL"
  }
} else {
  btc_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_TSI=TRUE
  system("sed -i 's/BTC_TSI_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/BTC_TSI_COL/limegreen/' ../index1.html")
} else {
  ens_TSI=FALSE
  system("sed -i 's/BTC_TSI_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/BTC_TSI_COL/red/' ../index1.html")
}

message(paste("BTC TSI signal:",btc_signal))
## BTC TSI signal: NONE
par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(tsi[,1] ~ as.Date(price2$date),type="l",col="blue",
  xlab="Date",ylab="TSI",main="TSI")
lines(as.Date(price2$date), tsi[,2]  , col="red"  )
grid()

par(mfrow=c(1,1))

BTC stochastic oscillator indicator

n <- as.numeric(unlist(strsplit(params[params$indicator == "stoch",2],",")))
n1 <- n[1]
n2 <- n[2]
n3 <- n[3]

sto <- stoch(HLC(price), nFastK=n1 , nFastD=n2 , nSlowD=n2 , bounded = TRUE, smooth=n3)

price2 <- cbind(price,sto)
price2$signal <- price2$fastK > price2$fastD

tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close fastK fastD slowD signal
2022-09-24 19310.20 18861.97 18937.01 0.1796336 0.3831576 0.5048215 FALSE
2022-09-25 19134.73 18696.47 18802.10 0.1544441 0.3717256 0.5032955 FALSE
2022-09-26 19274.87 18721.29 19222.67 0.1702777 0.3618812 0.5015223 FALSE
2022-09-27 20338.46 18915.67 19110.55 0.1916893 0.3537722 0.4995370 FALSE
2022-09-28 19688.34 18553.30 19426.72 0.1921901 0.3460807 0.4973039 FALSE
2022-09-29 19574.06 18924.35 19452.39 0.2162139 0.3392218 0.4947980 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    btc_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    btc_signal="SELL"
  }
} else {
  btc_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_stoch=TRUE
  system("sed -i 's/BTC_STOCH_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/BTC_STOCH_COL/limegreen/' ../index1.html")
} else {
  ens_stoch=FALSE
  system("sed -i 's/BTC_STOCH_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/BTC_STOCH_COL/red/' ../index1.html")
}

message(paste("BTC stoch signal:",btc_signal))
## BTC stoch signal: NONE
par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(price2$fastK ~ as.Date(price2$date),type="l",col="blue",
  xlab="Date",ylab="index",main="stochastic oscillator")
lines(as.Date(price2$date), price2$fastD  , col="red"  )
grid()

par(mfrow=c(1,1))

BTC double RSI indicator

n <- as.numeric(unlist(strsplit(params[params$indicator == "RSI2",2],",")))
n1 <- n[1]
n2 <- n[2]

rsi1 <- RSI(price$close,n=n1,maType=EMA)
rsi2 <- RSI(price$close,n=n2,maType=EMA)

price2 <- cbind(price,rsi1,rsi2)
price2$signal <- price2$rsi1 > price2$rsi2

tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close rsi1 rsi2 signal
2022-09-24 19310.20 18861.97 18937.01 42.36940 42.61492 FALSE
2022-09-25 19134.73 18696.47 18802.10 41.95434 42.38625 FALSE
2022-09-26 19274.87 18721.29 19222.67 43.73398 43.35395 TRUE
2022-09-27 20338.46 18915.67 19110.55 43.36684 43.15659 TRUE
2022-09-28 19688.34 18553.30 19426.72 44.72209 43.89217 TRUE
2022-09-29 19574.06 18924.35 19452.39 44.83309 43.95230 TRUE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    btc_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    btc_signal="SELL"
  }
} else {
  btc_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_RSI2=TRUE
  system("sed -i 's/BTC_RSI_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/BTC_RSI_COL/limegreen/' ../index1.html")
} else {
  ens_RSI2=FALSE
  system("sed -i 's/BTC_RSI_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/BTC_RSI_COL/red/' ../index1.html")
}

message(paste("BTC RSI signal:",btc_signal))
## BTC RSI signal: NONE
par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(price2$rsi1 ~ as.Date(price2$date),type="l",col="blue",
  xlab="Date",ylab="index",main="double RSI")
lines(as.Date(price2$date), price2$rsi2  , col="red"  )
grid()

par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(price2$rsi1/price2$rsi2 ~ as.Date(price2$date),type="l",
  xlab="Date",ylab="RSI ratio",main="double RSI")
grid()
abline(h=1,lty=2,lwd=2)

par(mfrow=c(1,1))

BTC Donchian channel indicator

n <- as.numeric(params[params$indicator == "DC",2])

price2 <- price[1:nrow(price)-1,]
dc <- DonchianChannel(price2$close,n=n)

price2$higher <- c(NA,sapply(2:nrow(dc),function(i) {
  dc[i,"high"] > dc[(i-1),"high"]
} ))
price2$lower <- c(NA,sapply(2:nrow(dc),function(i) {
  dc[i,"low"] < dc[(i-1),"low"]
} ))
price2 <- price2[price2$higher != price2$lower,]
# show changing rows only
price2 <- price2[c(NA,unlist(lapply(2:nrow(price2) , function(i) {
  price2$higher[i] != price2$higher[i-1]
}))),]
price2 <- price2[!is.na(price2$higher),]

previous_signal <- price2[nrow(price2),"higher"]

price2 <- price
dc <- DonchianChannel(price2$close,n=n)
colnames(dc) <- c("dchigh","dcmid","dclow")
price2 <- cbind(price2,dc)

tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close dchigh dcmid dclow
2022-09-24 19310.20 18861.97 18937.01 22370.45 20458.92 18547.4
2022-09-25 19134.73 18696.47 18802.10 22370.45 20458.92 18547.4
2022-09-26 19274.87 18721.29 19222.67 22370.45 20458.92 18547.4
2022-09-27 20338.46 18915.67 19110.55 22370.45 20458.92 18547.4
2022-09-28 19688.34 18553.30 19426.72 22370.45 20458.92 18547.4
2022-09-29 19574.06 18924.35 19452.39 22370.45 20458.92 18547.4
btc_signal="NONE"

# if we in negative territory, check whether time to buy
if ( previous_signal == FALSE ) {
  if ( price2[nrow(price2),"dchigh"] > price2[nrow(price2)-1,"dchigh"] ) {
    btc_signal="BUY"
  }
}

# if we in positive territory, check whether time to sell
if ( previous_signal == TRUE ) {
  if ( price2[nrow(price2),"dclow"] < price2[nrow(price2)-1,"dclow"] ) {
    btc_signal="SELL"
  }
}

if ( btc_signal=="NONE" ) {
  today_signal=previous_signal
} else {
  if (btc_signal=="BUY") { today_signal = TRUE }
  if (btc_signal=="SELL") { today_signal = FALSE }
}

if (today_signal==TRUE) {
  ens_DC=TRUE
  system("sed -i 's/BTC_DC_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/BTC_DC_COL/limegreen/' ../index1.html")
} else {
  ens_DC=FALSE
  system("sed -i 's/BTC_DC_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/BTC_DC_COL/red/' ../index1.html")
}

message(paste("BTC DC signal:",btc_signal))
## BTC DC signal: NONE
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price",lwd=2)
grid()

lines(price2$dclow~ as.Date(price2$date),lwd=1.5,col="red")
lines(price2$dchigh~ as.Date(price2$date),lwd=1.5,col="limegreen")

price2 <- tail(price2,100)

plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price",lwd=2)
grid()

lines(price2$dclow~ as.Date(price2$date),lwd=1.5,col="red")
lines(price2$dcmid~ as.Date(price2$date),lwd=1.5,col="gray")
lines(price2$dchigh~ as.Date(price2$date),lwd=1.5,col="limegreen")

BTC KST indicator

Another high-performing indicator across different price series data.

price2 <- price

n <- as.numeric(unlist(strsplit(params[params$indicator == "KST",2],",")))
nScale <- n[1]
nrocScale <- n[2]
nSigs <- n[3]

kst <- KST(price2$close,n=nScale * c(10, 10, 10, 15) ,
  nROC=nrocScale * c(10, 15, 20, 30),
  nSig=nSigs)

price2 <- cbind(price2,kst)
price2$KST <- as.numeric(kst[,1]>kst[,2])

tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close kst signal KST
2022-09-24 19310.20 18861.97 18937.01 -4.267549 -10.533729 1
2022-09-25 19134.73 18696.47 18802.10 -4.970936 -9.565604 1
2022-09-26 19274.87 18721.29 19222.67 -8.278076 -8.725006 1
2022-09-27 20338.46 18915.67 19110.55 -11.979918 -7.983860 0
2022-09-28 19688.34 18553.30 19426.72 -13.046608 -7.543171 0
2022-09-29 19574.06 18924.35 19452.39 -13.676157 -7.404482 0
today_signal <- price2[nrow(price2),"KST"]
previous_signal <- price2[(nrow(price2)-1),"KST"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    btc_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    btc_signal="SELL"
  }
} else {
  btc_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_KST=TRUE
  system("sed -i 's/BTC_KST_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/BTC_KST_COL/limegreen/' ../index1.html")
} else {
  ens_KST=FALSE
  system("sed -i 's/BTC_KST_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/BTC_KST_COL/red/' ../index1.html")
}

message(paste("BTC KST signal:",btc_signal))
## BTC KST signal: NONE
par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(kst[,1] ~ as.Date(price2$date),type="l",col="blue",
  xlab="Date",ylab="KST",main="KST")
lines(as.Date(price2$date), kst[,2]  , col="red"  )
grid()

par(mfrow=c(1,1))

BTC Ensemble indicator

This is a combination of a number of indicators.

ens <- params[params$indicator=="Ensemble","parameter"]
myrev <- intToUtf8(rev(utf8ToInt(ens)))
myrev <- unlist(strsplit(myrev,","))
# get thresh
n <- as.numeric(myrev[1])
myrev <- myrev[2:length(myrev)]
# get combination
combo <- sapply(myrev,function(s) { intToUtf8(rev(utf8ToInt(s))) })

message(paste("The combination is",paste(combo,collapse=" ")))
## The combination is KST DC stoch TSI DMI EMAcross SMAcross
message(paste("The buy threshold is",n))
## The buy threshold is 2
indicators <- c("SMA"=ens_SMA,
  "EMA"=ens_EMA,
  "SMAcross"=ens_SMAcross,
  "EMAcross"=ens_EMAcross,
  "DMI"=ens_DMI,
  "TSI"=ens_TSI,
  "stoch"=ens_stoch,
  "RSI2"=ens_RSI2,
  "DC"=ens_DC,
  "KST"=ens_KST)

indicators <- indicators[names(indicators) %in% combo]
message("State of the indicators:")
## State of the indicators:
indicators
## SMAcross EMAcross      DMI      TSI    stoch       DC      KST 
##    FALSE    FALSE    FALSE     TRUE    FALSE    FALSE    FALSE
today_count <- sum(indicators)
message(paste("today_count_BTC",today_count,sep="="))
## today_count_BTC=1
today_signal <- today_count>=n

prev_html <- readLines("https://mdz-analytics.com/crypto/alerts.html")
prev_signal <- length(grep("BTC ensemble indicator is BULLISH",prev_html))>1

btc_signal <- "NONE"

if ( today_signal != prev_signal ) {
  if ( today_signal == TRUE ) {
    btc_signal="BUY"
  } else {
    btc_signal="SELL"
  }
}

if (today_signal==TRUE) {
  system("sed -i 's/BTC_ENS_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/BTC_ENS_COL/limegreen/' ../index1.html")
  message("BTC ensemble indicator is BULLISH")
} else {
  system("sed -i 's/BTC_ENS_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/BTC_ENS_COL/red/' ../index1.html")
  message("BTC ensemble indicator is BEARISH")
}
## BTC ensemble indicator is BEARISH
message(paste("BTC ENS signal:",btc_signal))
## BTC ENS signal: SELL

ETH

Get price data

Obtaining ETH historical data (daily).

Ethereum is the largest and oldest smart contract blockchain network.

URL="https://web-api.coinmarketcap.com/v1/cryptocurrency/ohlcv/historical?symbol=ETH&convert=USD&interval=daily&count=300"
download.file(URL,destfile="ethdat.txt")
ethdat <- fromJSON("ethdat.txt")
price <- ethdat$data$quotes
price <- data.frame( as.Date(price$time_close) , price$quote$USD$high, price$quote$USD$low, price$quote$USD$close)
colnames(price) <- c("date","high","low","close")

URL="https://web-api.coinmarketcap.com/v1/cryptocurrency/ohlcv/historical?symbol=ETH&convert=USD&interval=hourly&time_period=hourly&count=11"
download.file(URL,destfile="ethdat.txt")
ethdat <- fromJSON("ethdat.txt")
price2 <- ethdat$data$quotes
price2 <- data.frame( as.Date(price2$time_close)  , price2$quote$USD$high, price2$quote$USD$low, price2$quote$USD$close,stringsAsFactors=FALSE)
colnames(price2) <- c("date","high","low","close")

high <- max(price2[,2])
low <- min(price2[,3])
close <- price2[nrow(price2),4]

df <- data.frame(date=Sys.Date(),high=high,low=low,close=close,stringsAsFactors=FALSE)
price <- rbind(price,df)
tail(price) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close
2022-09-24 1346.255 1312.640 1317.993
2022-09-25 1333.371 1275.628 1294.217
2022-09-26 1335.526 1282.049 1335.320
2022-09-27 1396.892 1308.991 1330.128
2022-09-28 1351.965 1267.869 1337.411
2022-09-29 1343.665 1293.193 1329.132
if ( TESTING == TRUE) {
  price[nrow(price),"Close"] <- price[nrow(price),"Close"] * 2
}

Fetch backtested parameters.

params <- read.table("https://mdz-analytics.com/coins/ETH/ETH_dat.txt", header=TRUE)
params %>% kbl(caption="ETH optimised backtested parameters") %>%  kable_styling("hover", full_width = F)
ETH optimised backtested parameters
indicator parameter meanROI totalROI ntrades ndays xhodl
SMA 34 1.722584 25090.450 69 2608 52.19604
EMA 17 1.151307 11986.489 135 2608 24.93567
SMAcross 21,12 1.492163 29253.179 55 2608 60.85583
EMAcross 16,13 2.532101 32319.366 32 2608 67.23447
DMI 16 1.842772 15390.796 63 2608 32.01771
DC 11 1.496811 25027.537 53 2608 52.06516
TSI 93,14,19 1.482050 10018.496 40 2608 20.84163
stoch 27,49,2 1.168702 11441.323 92 2608 23.80156
RSI2 103,107 1.415959 7572.955 62 2608 15.75413
KST 1.5,0.56,24 1.372597 14250.353 51 2608 29.64522
Ensemble SMAcross,EMA,DMI,stoch,RSI2,DC,KST,4 1.370224 56395.454 74 2608 149.73742

ETH SMA indicator

Now to determine whether ETH has crossed the SMA line.

price2 <- price

n <- as.numeric(params[params$indicator == "SMA",2])

price2$ma <- SMA(Cl(price2),n=n)
price2$signal <- price2$close > price2$ma
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close ma signal
2022-09-24 1346.255 1312.640 1317.993 1537.213 FALSE
2022-09-25 1333.371 1275.628 1294.217 1527.558 FALSE
2022-09-26 1335.526 1282.049 1335.320 1517.927 FALSE
2022-09-27 1396.892 1308.991 1330.128 1508.311 FALSE
2022-09-28 1351.965 1267.869 1337.411 1497.751 FALSE
2022-09-29 1343.665 1293.193 1329.132 1492.497 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    eth_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    eth_signal="SELL"
  }
} else {
  eth_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_SMA=TRUE
  system("sed -i 's/ETH_SMA_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/ETH_SMA_COL/limegreen/' ../index1.html")
} else {
  ens_SMA=FALSE
  system("sed -i 's/ETH_SMA_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/ETH_SMA_COL/red/' ../index1.html")
}

message(paste("ETH SMA signal:",eth_signal))
## ETH SMA signal: NONE
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="ETH SMA")
grid()
lines(price2$ma~ as.Date(price2$date) ,col="red")

ETH EMA indicator

Now to determine whether ETH has crossed the EMA line.

price2 <- price

n <- as.numeric(params[params$indicator == "EMA",2])

price2$ma <- EMA(Cl(price2),n=n)
price2$signal <- price2$close > price2$ma
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close ma signal
2022-09-24 1346.255 1312.640 1317.993 1439.071 FALSE
2022-09-25 1333.371 1275.628 1294.217 1422.977 FALSE
2022-09-26 1335.526 1282.049 1335.320 1413.237 FALSE
2022-09-27 1396.892 1308.991 1330.128 1404.003 FALSE
2022-09-28 1351.965 1267.869 1337.411 1396.603 FALSE
2022-09-29 1343.665 1293.193 1329.132 1389.107 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    eth_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    eth_signal="SELL"
  }
} else {
  eth_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_EMA=TRUE
  system("sed -i 's/ETH_EMA_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/ETH_EMA_COL/limegreen/' ../index1.html")
} else {
  ens_EMA=FALSE
  system("sed -i 's/ETH_EMA_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/ETH_EMA_COL/red/' ../index1.html")
}

message(paste("ETH EMA signal:",eth_signal))
## ETH EMA signal: NONE
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="ETH EMA")
grid()
lines(price2$ma~ as.Date(price2$date) ,col="red")

ETH SMA cross indicator

The SMA cross is a highly profitable strategy.

price2 <- price

n <- as.numeric(unlist(strsplit(params[params$indicator == "SMAcross",2],",")))
n1 <- n[1]
n2 <- n[2]

price2$ma1 <- SMA(Cl(price2),n=n1)
price2$ma2 <- SMA(Cl(price2),n=n2)

price2$signal <- price2$ma2 > price2$ma1
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close ma1 ma2 signal
2022-09-24 1346.255 1312.640 1317.993 1516.472 1404.435 FALSE
2022-09-25 1333.371 1275.628 1294.217 1502.975 1380.555 FALSE
2022-09-26 1335.526 1282.049 1335.320 1489.553 1355.602 FALSE
2022-09-27 1396.892 1308.991 1330.128 1478.524 1343.804 FALSE
2022-09-28 1351.965 1267.869 1337.411 1464.595 1335.885 FALSE
2022-09-29 1343.665 1293.193 1329.132 1450.014 1324.167 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    eth_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    eth_signal="SELL"
  }
} else {
eth_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_SMAcross=TRUE
  system("sed -i 's/ETH_SMACROSS_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/ETH_SMACROSS_COL/limegreen/' ../index1.html")
} else {
  ens_SMAcross=FALSE
  system("sed -i 's/ETH_SMACROSS_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/ETH_SMACROSS_COL/red/' ../index1.html")
}

message(paste("ETH SMA cross signal:",eth_signal))
## ETH SMA cross signal: NONE
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="ETH SMA cross")
grid()
lines(price2$ma1~ as.Date(price2$date) ,col="red")
lines(price2$ma2~ as.Date(price2$date) ,col="blue")

ETH EMA cross indicator

The EMA cross is a highly profitable strategy.

price2 <- price

n <- as.numeric(unlist(strsplit(params[params$indicator == "EMAcross",2],",")))
n1 <- n[1]
n2 <- n[2]

price2$ma1 <- EMA(Cl(price2),n=n1)
price2$ma2 <- EMA(Cl(price2),n=n2)

price2$signal <- price2$ma2 > price2$ma1
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close ma1 ma2 signal
2022-09-24 1346.255 1312.640 1317.993 1432.059 1408.395 FALSE
2022-09-25 1333.371 1275.628 1294.217 1415.843 1392.083 FALSE
2022-09-26 1335.526 1282.049 1335.320 1406.369 1383.974 FALSE
2022-09-27 1396.892 1308.991 1330.128 1397.400 1376.282 FALSE
2022-09-28 1351.965 1267.869 1337.411 1390.342 1370.729 FALSE
2022-09-29 1343.665 1293.193 1329.132 1383.141 1364.787 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    eth_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    eth_signal="SELL"
  }
} else {
eth_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_EMAcross=TRUE
  system("sed -i 's/ETH_EMACROSS_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/ETH_EMACROSS_COL/limegreen/' ../index1.html")
} else {
  ens_EMAcross=FALSE
  system("sed -i 's/ETH_EMACROSS_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/ETH_EMACROSS_COL/red/' ../index1.html")
}

message(paste("ETH EMA cross signal:",eth_signal))
## ETH EMA cross signal: NONE
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="ETH EMA cross")
grid()
lines(price2$ma1~ as.Date(price2$date) ,col="red")
lines(price2$ma2~ as.Date(price2$date) ,col="blue")

ETH DMI

n <- as.numeric(params[params$indicator == "DMI",2])

dmi.adx <- ADX(price[,c("high","low","close")],n=n)
price2 <- cbind(price,dmi.adx)
price2$signal <- dmi.adx[,1] > dmi.adx[,2]
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close DIp DIn DX ADX signal
2022-09-24 1346.255 1312.640 1317.993 12.38041 29.35322 40.66936 24.05796 FALSE
2022-09-25 1333.371 1275.628 1294.217 11.89462 30.71656 44.17135 25.31505 FALSE
2022-09-26 1335.526 1282.049 1335.320 11.60114 29.57035 43.64478 26.46066 FALSE
2022-09-27 1396.892 1308.991 1330.128 15.17572 27.75453 29.30057 26.63815 FALSE
2022-09-28 1351.965 1267.869 1337.411 14.28080 29.00146 34.01082 27.09894 FALSE
2022-09-29 1343.665 1293.193 1329.132 13.76129 27.94643 34.01082 27.53093 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    eth_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    eth_signal="SELL"
  }
} else {
  eth_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_DMI=TRUE
  system("sed -i 's/ETH_DMI_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/ETH_DMI_COL/limegreen/' ../index1.html")
} else {
  ens_DMI=FALSE
  system("sed -i 's/ETH_DMI_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/ETH_DMI_COL/red/' ../index1.html")
}

message(paste("ETH DMI signal:",eth_signal))
## ETH DMI signal: NONE
par(mfrow=c(2,1))
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="ETH USD price")
grid()
plot(price2$DIp~as.Date(price2$date),type="l", col="blue",
  xlab="Date",ylab="price (USD)",main="ETH DMI")
grid()
lines(price2$DIn ~ as.Date(price2$date) ,col="red")

ETH TSI indicator

Best indicator.

n <- as.numeric(unlist(strsplit(params[params$indicator == "TSI",2],",")))
n1 <- n[1]
n2 <- n[2]
ns <- n[3]

tsi <- TSI(price$close , n.first = n1, n.second = n2, n.signal = ns )
colnames(tsi) <- c("tsi","sig")

price2 <- cbind(price,tsi)
price2$signal <- tsi[,1] > tsi[,2]
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close tsi sig signal
2022-09-24 1346.255 1312.640 1317.993 -8.881822 -5.217921 FALSE
2022-09-25 1333.371 1275.628 1294.217 -9.318678 -5.627997 FALSE
2022-09-26 1335.526 1282.049 1335.320 -9.473622 -6.012559 FALSE
2022-09-27 1396.892 1308.991 1330.128 -9.629369 -6.374240 FALSE
2022-09-28 1351.965 1267.869 1337.411 -9.723936 -6.709210 FALSE
2022-09-29 1343.665 1293.193 1329.132 -9.842663 -7.022555 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    eth_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    eth_signal="SELL"
  }
} else {
  eth_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_TSI=TRUE
  system("sed -i 's/ETH_TSI_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/ETH_TSI_COL/limegreen/' ../index1.html")
} else {
  ens_TSI=FALSE
  system("sed -i 's/ETH_TSI_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/ETH_TSI_COL/red/' ../index1.html")
}

message(paste("ETH TSI signal:",eth_signal))
## ETH TSI signal: NONE
par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(tsi[,1] ~ as.Date(price2$date),type="l",col="blue",
  xlab="Date",ylab="TSI",main="TSI")
lines(as.Date(price2$date), tsi[,2]  , col="red"  )
grid()

par(mfrow=c(1,1))

ETH stochastic oscillator indicator

n <- as.numeric(unlist(strsplit(params[params$indicator == "stoch",2],",")))
n1 <- n[1]
n2 <- n[2]
n3 <- n[3]

sto <- stoch(HLC(price), nFastK=n1 , nFastD=n2 , nSlowD=n2 , bounded = TRUE, smooth=n3)

price2 <- cbind(price,sto)
price2$signal <- price2$fastK > price2$fastD

tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close fastK fastD slowD signal
2022-09-24 1346.255 1312.640 1317.993 0.1688066 0.4137845 0.6340414 FALSE
2022-09-25 1333.371 1275.628 1294.217 0.1381414 0.3983319 0.6301123 FALSE
2022-09-26 1335.526 1282.049 1335.320 0.1537493 0.3824714 0.6255580 FALSE
2022-09-27 1396.892 1308.991 1330.128 0.1860974 0.3676802 0.6204086 FALSE
2022-09-28 1351.965 1267.869 1337.411 0.1879806 0.3528598 0.6146480 FALSE
2022-09-29 1343.665 1293.193 1329.132 0.1870839 0.3371956 0.6082457 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    eth_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    eth_signal="SELL"
  }
} else {
  eth_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_stoch=TRUE
  system("sed -i 's/ETH_STOCH_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/ETH_STOCH_COL/limegreen/' ../index1.html")
} else {
  ens_stoch=FALSE
  system("sed -i 's/ETH_STOCH_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/ETH_STOCH_COL/red/' ../index1.html")
}

message(paste("ETH stoch signal:",eth_signal))
## ETH stoch signal: NONE
par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(price2$fastK ~ as.Date(price2$date),type="l",col="blue",
  xlab="Date",ylab="index",main="stochastic oscillator")
lines(as.Date(price2$date), price2$fastD  , col="red"  )
grid()

par(mfrow=c(1,1))

ETH double RSI indicator

n <- as.numeric(unlist(strsplit(params[params$indicator == "RSI2",2],",")))
n1 <- n[1]
n2 <- n[2]

rsi1 <- RSI(price$close,n=n1,maType=EMA)
rsi2 <- RSI(price$close,n=n2,maType=EMA)

price2 <- cbind(price,rsi1,rsi2)
price2$signal <- price2$rsi1 > price2$rsi2

tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close rsi1 rsi2 signal
2022-09-24 1346.255 1312.640 1317.993 44.33661 44.34582 FALSE
2022-09-25 1333.371 1275.628 1294.217 43.98744 44.01175 FALSE
2022-09-26 1335.526 1282.049 1335.320 44.75435 44.74491 TRUE
2022-09-27 1396.892 1308.991 1330.128 44.67556 44.66962 TRUE
2022-09-28 1351.965 1267.869 1337.411 44.81450 44.80235 TRUE
2022-09-29 1343.665 1293.193 1329.132 44.68444 44.67823 TRUE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    eth_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    eth_signal="SELL"
  }
} else {
  eth_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_RSI2=TRUE
  system("sed -i 's/ETH_RSI_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/ETH_RSI_COL/limegreen/' ../index1.html")
} else {
  ens_RSI2=FALSE
  system("sed -i 's/ETH_RSI_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/ETH_RSI_COL/red/' ../index1.html")
}

message(paste("ETH RSI signal:",eth_signal))
## ETH RSI signal: NONE
par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(price2$rsi1 ~ as.Date(price2$date),type="l",col="blue",
  xlab="Date",ylab="index",main="double RSI")
lines(as.Date(price2$date), price2$rsi2  , col="red"  )
grid()

par(mfrow=c(1,1))

par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(price2$rsi1/price2$rsi2 ~ as.Date(price2$date),type="l",
  xlab="Date",ylab="RSI ratio",main="double RSI")
grid()
abline(h=1,lty=2,lwd=2)

par(mfrow=c(1,1))

ETH Donchian channel indicator

n <- as.numeric(params[params$indicator == "DC",2])

price2 <- price[1:nrow(price)-1,]
dc <- DonchianChannel(price2$close,n=n)

price2$higher <- c(NA,sapply(2:nrow(dc),function(i) {
  dc[i,"high"] > dc[(i-1),"high"]
} ))
price2$lower <- c(NA,sapply(2:nrow(dc),function(i) {
  dc[i,"low"] < dc[(i-1),"low"]
} ))
price2 <- price2[price2$higher != price2$lower,]
# show changing rows only
price2 <- price2[c(NA,unlist(lapply(2:nrow(price2) , function(i) {
  price2$higher[i] != price2$higher[i-1]
}))),]
price2 <- price2[!is.na(price2$higher),]

previous_signal <- price2[nrow(price2),"higher"]

price2 <- price
dc <- DonchianChannel(price2$close,n=n)
colnames(dc) <- c("dchigh","dcmid","dclow")
price2 <- cbind(price2,dc)

tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close dchigh dcmid dclow
2022-09-24 1346.255 1312.640 1317.993 1634.755 1443.681 1252.608
2022-09-25 1333.371 1275.628 1294.217 1471.693 1362.151 1252.608
2022-09-26 1335.526 1282.049 1335.320 1469.742 1361.175 1252.608
2022-09-27 1396.892 1308.991 1330.128 1469.742 1361.175 1252.608
2022-09-28 1351.965 1267.869 1337.411 1377.541 1315.075 1252.608
2022-09-29 1343.665 1293.193 1329.132 1377.541 1315.075 1252.608
eth_signal="NONE"

# if we in negative territory, check whether time to buy
if ( previous_signal == FALSE ) {
  if ( price2[nrow(price2),"dchigh"] > price2[nrow(price2)-1,"dchigh"] ) {
    eth_signal="BUY"
  }
}

# if we in positive territory, check whether time to sell
if ( previous_signal == TRUE ) {
  if ( price2[nrow(price2),"dclow"] < price2[nrow(price2)-1,"dclow"] ) {
    eth_signal="SELL"
  }
}

if ( eth_signal=="NONE" ) {
  today_signal=previous_signal
} else {
  if (eth_signal=="BUY") { today_signal = TRUE }
  if (eth_signal=="SELL") { today_signal = FALSE }
}

if (today_signal==TRUE) {
  ens_DC=TRUE
  system("sed -i 's/ETH_DC_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/ETH_DC_COL/limegreen/' ../index1.html")
} else {
  ens_DC=FALSE
  system("sed -i 's/ETH_DC_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/ETH_DC_COL/red/' ../index1.html")
}

message(paste("ETH DC signal:",eth_signal))
## ETH DC signal: NONE
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price",lwd=2)
grid()

lines(price2$dclow~ as.Date(price2$date),lwd=1.5,col="red")
lines(price2$dchigh~ as.Date(price2$date),lwd=1.5,col="limegreen")

price2 <- tail(price2,100)

plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price",lwd=2)
grid()

lines(price2$dclow~ as.Date(price2$date),lwd=1.5,col="red")
lines(price2$dcmid~ as.Date(price2$date),lwd=1.5,col="gray")
lines(price2$dchigh~ as.Date(price2$date),lwd=1.5,col="limegreen")

ETH KST indicator

Another high-performing indicator across different price series data.

price2 <- price

n <- as.numeric(unlist(strsplit(params[params$indicator == "KST",2],",")))
nScale <- n[1]
nrocScale <- n[2]
nSigs <- n[3]

kst <- KST(price2$close,n=nScale * c(10, 10, 10, 15) ,
  nROC=nrocScale * c(10, 15, 20, 30),
  nSig=nSigs)

price2 <- cbind(price2,kst)
price2$KST <- as.numeric(kst[,1]>kst[,2])

tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close kst signal KST
2022-09-24 1346.255 1312.640 1317.993 -78.68506 -48.57802 0
2022-09-25 1333.371 1275.628 1294.217 -92.48944 -49.17170 0
2022-09-26 1335.526 1282.049 1335.320 -103.65274 -49.83666 0
2022-09-27 1396.892 1308.991 1330.128 -114.01886 -50.85419 0
2022-09-28 1351.965 1267.869 1337.411 -119.00970 -52.19723 0
2022-09-29 1343.665 1293.193 1329.132 -122.66960 -53.93107 0
today_signal <- price2[nrow(price2),"KST"]
previous_signal <- price2[(nrow(price2)-1),"KST"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    eth_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    eth_signal="SELL"
  }
} else {
  eth_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_KST=TRUE
  system("sed -i 's/ETH_KST_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/ETH_KST_COL/limegreen/' ../index1.html")
} else {
  ens_KST=FALSE
  system("sed -i 's/ETH_KST_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/ETH_KST_COL/red/' ../index1.html")
}

message(paste("ETH KST signal:",eth_signal))
## ETH KST signal: NONE
par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(kst[,1] ~ as.Date(price2$date),type="l",col="blue",
  xlab="Date",ylab="KST",main="KST")
lines(as.Date(price2$date), kst[,2]  , col="red"  )
grid()

par(mfrow=c(1,1))

ETH Ensembl indicator

This is a combination of a number of n=y indicators, where x/y are a buy/sell threshold.

ens <- params[params$indicator=="Ensemble","parameter"]
myrev <- intToUtf8(rev(utf8ToInt(ens)))
myrev <- unlist(strsplit(myrev,","))
# get thresh
n <- as.numeric(myrev[1])
myrev <- myrev[2:length(myrev)]
# get combination
combo <- sapply(myrev,function(s) { intToUtf8(rev(utf8ToInt(s))) })

message(paste("The combination is",paste(combo,collapse=" ")))
## The combination is KST DC RSI2 stoch DMI EMA SMAcross
message(paste("The buy threshold is",n))
## The buy threshold is 4
indicators <- c("SMA"=ens_SMA,
  "EMA"=ens_EMA,
  "SMAcross"=ens_SMAcross,
  "EMAcross"=ens_EMAcross,
  "DMI"=ens_DMI,
  "TSI"=ens_TSI,
  "stoch"=ens_stoch,
  "RSI2"=ens_RSI2,
  "DC"=ens_DC,
  "KST"=ens_KST)

indicators <- indicators[names(indicators) %in% combo]
message("State of the indicators:")
## State of the indicators:
indicators
##      EMA SMAcross      DMI    stoch     RSI2       DC      KST 
##    FALSE    FALSE    FALSE    FALSE     TRUE    FALSE    FALSE
today_count <- sum(indicators)
message(paste("today_count_ETH",today_count,sep="="))
## today_count_ETH=1
today_signal <- today_count>=n

prev_signal <- length(grep("ETH ensemble indicator is BULLISH",prev_html))>1

eth_signal <- "NONE"

if ( today_signal != prev_signal ) {
  if ( today_signal == TRUE ) {
    eth_signal="BUY"
  } else {
    eth_signal="SELL"
  }
}

if (today_signal==TRUE) {
  system("sed -i 's/ETH_ENS_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/ETH_ENS_COL/limegreen/' ../index1.html")
  message("ETH ensemble indicator is BULLISH")
} else {
  system("sed -i 's/ETH_ENS_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/ETH_ENS_COL/red/' ../index1.html")
  message("ETH ensemble indicator is BEARISH")
}
## ETH ensemble indicator is BEARISH
message(paste("ETH ENS signal:",eth_signal))
## ETH ENS signal: SELL

XMR

Get price data

Obtaining XMR price data (daily) for the last 300 days.

XMR is the ticker for Monero, the largest and oldest private cryptocurrency which aims to be the private p2p cash of the internet.

URL="https://web-api.coinmarketcap.com/v1/cryptocurrency/ohlcv/historical?symbol=XMR&convert=USD&interval=daily&count=300"
download.file(URL,destfile="xmrdat.txt")
dat <- fromJSON("xmrdat.txt")
price <- dat$data$quotes
price <- data.frame(  as.Date(price$time_close) , price$quote$USD$high, price$quote$USD$low, price$quote$USD$close)
colnames(price) <- c("date","high","low","close")

URL="https://web-api.coinmarketcap.com/v1/cryptocurrency/ohlcv/historical?symbol=XMR&convert=USD&interval=hourly&time_period=hourly&count=11"
download.file(URL,destfile="xmrdat.txt")
dat <- fromJSON("xmrdat.txt")
price2 <- dat$data$quotes
price2 <- data.frame( as.Date(price2$time_close) , price2$quote$USD$high, price2$quote$USD$low, price2$quote$USD$close,stringsAsFactors=FALSE)
colnames(price2) <- c("date","high","low","close")

high <- max(price2[,2])
low <-  min(price2[,3])
close <- price2[nrow(price2),4]

df <- data.frame(date=mydate,high=high,low=low,close=close,stringsAsFactors=FALSE)
price <- rbind(price,df)
tail(price) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close
2022-09-24 143.9085 140.7304 141.7651
2022-09-25 144.5276 140.1472 141.1041
2022-09-26 146.1058 139.9758 145.7094
2022-09-27 152.8920 143.1812 144.6130
2022-09-28 147.9419 140.3032 147.2961
2022-09-29 149.1473 146.7070 147.5753
if ( TESTING == TRUE) {
  price[nrow(price),"close"] <- price[nrow(price),"close"] * 2
}

Now fetch the backtested parameters.

params <- read.table("https://mdz-analytics.com/coins/XMR/XMR_dat.txt", header=TRUE)
params %>% kbl(caption="XMR optimised backtested parameters") %>%  kable_styling("hover", full_width = F)
XMR optimised backtested parameters
indicator parameter meanROI totalROI ntrades ndays xhodl
SMA 26 1.081940 89.80789 136 3050 0.9986643
EMA 19 1.063057 116.41114 177 3050 1.2944926
SMAcross 188,118 40.788815 2193.13683 7 3050 24.3876959
EMAcross 74,7 1.591188 747.85506 25 3050 8.3161532
DMI 66 2.049948 700.15611 23 3050 7.7857406
DC 28 1.408096 453.01425 28 3050 5.0375215
TSI 81,23,4 1.160863 1129.21810 87 3050 12.5569127
stoch 17,60,6 1.196081 995.63657 74 3050 11.0714852
RSI2 32,89 1.093143 469.80768 143 3050 5.2242645
KST 1.2,0.18,49 1.214472 3246.12909 74 3050 36.0969767
Ensemble EMAcross,TSI,stoch,RSI2,DC,KST,3 1.173126 2206.94324 86 3050 40.7347497

XMR SMA indicator

Now to determine whether XMR has crossed the SMA line.

price2 <- price

n <- as.numeric(params[params$indicator == "SMA",2])

price2$ma <- SMA(Cl(price2),n=n)
price2$signal <- price2$close > price2$ma
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close ma signal
2022-09-24 143.9085 140.7304 141.7651 149.3779 FALSE
2022-09-25 144.5276 140.1472 141.1041 149.0860 FALSE
2022-09-26 146.1058 139.9758 145.7094 148.9583 FALSE
2022-09-27 152.8920 143.1812 144.6130 148.6020 FALSE
2022-09-28 147.9419 140.3032 147.2961 148.3655 FALSE
2022-09-29 149.1473 146.7070 147.5753 148.1050 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    xmr_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    xmr_signal="SELL"
  }
} else {
xmr_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_SMA=TRUE
  system("sed -i 's/XMR_SMA_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/XMR_SMA_COL/limegreen/' ../index1.html")
} else {
  ens_SMA=FALSE
  system("sed -i 's/XMR_SMA_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/XMR_SMA_COL/red/' ../index1.html")
}

message(paste("XMR SMA signal:",xmr_signal))
## XMR SMA signal: NONE
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="XMR SMA")
grid()
lines(price2$ma~ as.Date(price2$date) ,col="red")

XMR EMA indicator

Now to determine whether XMR has crossed the EMA line.

price2 <- price

n <- as.numeric(params[params$indicator == "EMA",2])

price2$ma <- EMA(Cl(price2),n=n)
price2$signal <- price2$close > price2$ma
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close ma signal
2022-09-24 143.9085 140.7304 141.7651 146.3076 FALSE
2022-09-25 144.5276 140.1472 141.1041 145.7873 FALSE
2022-09-26 146.1058 139.9758 145.7094 145.7795 FALSE
2022-09-27 152.8920 143.1812 144.6130 145.6629 FALSE
2022-09-28 147.9419 140.3032 147.2961 145.8262 TRUE
2022-09-29 149.1473 146.7070 147.5753 146.0011 TRUE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    xmr_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    xmr_signal="SELL"
  }
} else {
xmr_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_EMA=TRUE
  system("sed -i 's/XMR_EMA_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/XMR_EMA_COL/limegreen/' ../index1.html")
} else {
  ens_EMA=FALSE
  system("sed -i 's/XMR_EMA_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/XMR_EMA_COL/red/' ../index1.html")
}

message(paste("XMR EMA signal:",xmr_signal))
## XMR EMA signal: NONE
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="XMR EMA")
grid()
lines(price2$ma~ as.Date(price2$date) ,col="red")

XMR SMA cross indicator

The SMA cross is a highly profitable strategy.

price2 <- price

n <- as.numeric(unlist(strsplit(params[params$indicator == "SMAcross",2],",")))
n1 <- n[1]
n2 <- n[2]

price2$ma1 <- SMA(Cl(price2),n=n1)
price2$ma2 <- SMA(Cl(price2),n=n2)

price2$signal <- price2$ma2 > price2$ma1
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close ma1 ma2 signal
2022-09-24 143.9085 140.7304 141.7651 171.0662 148.3105 FALSE
2022-09-25 144.5276 140.1472 141.1041 170.7963 147.7758 FALSE
2022-09-26 146.1058 139.9758 145.7094 170.5402 147.3280 FALSE
2022-09-27 152.8920 143.1812 144.6130 170.2595 146.8703 FALSE
2022-09-28 147.9419 140.3032 147.2961 169.9583 146.4119 FALSE
2022-09-29 149.1473 146.7070 147.5753 169.6805 146.0186 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    xmr_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    xmr_signal="SELL"
  }
} else {
xmr_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_SMAcross=TRUE
  system("sed -i 's/XMR_SMACROSS_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/XMR_SMACROSS_COL/limegreen/' ../index1.html")
} else {
  ens_SMAcross=FALSE
  system("sed -i 's/XMR_SMACROSS_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/XMR_SMACROSS_COL/red/' ../index1.html")
}

message(paste("XMR SMA cross signal is",xmr_signal))
## XMR SMA cross signal is NONE
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="XMR SMA cross")
grid()
lines(price2$ma1~ as.Date(price2$date) ,col="red")
lines(price2$ma2~ as.Date(price2$date) ,col="blue")

XMR EMA cross indicator

The EMA cross is a moderately profitable strategy.

price2 <- price

n <- as.numeric(unlist(strsplit(params[params$indicator == "EMAcross",2],",")))
n1 <- n[1]
n2 <- n[2]

price2$ma1 <- EMA(Cl(price2),n=n1)
price2$ma2 <- EMA(Cl(price2),n=n2)

price2$signal <- price2$ma2 > price2$ma1
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close ma1 ma2 signal
2022-09-24 143.9085 140.7304 141.7651 151.4089 142.4285 FALSE
2022-09-25 144.5276 140.1472 141.1041 151.1341 142.0974 FALSE
2022-09-26 146.1058 139.9758 145.7094 150.9894 143.0004 FALSE
2022-09-27 152.8920 143.1812 144.6130 150.8194 143.4035 FALSE
2022-09-28 147.9419 140.3032 147.2961 150.7254 144.3767 FALSE
2022-09-29 149.1473 146.7070 147.5753 150.6414 145.1763 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    xmr_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    xmr_signal="SELL"
  }
} else {
xmr_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_EMAcross=TRUE
  system("sed -i 's/XMR_EMACROSS_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/XMR_EMACROSS_COL/limegreen/' ../index1.html")
} else {
  ens_EMAcross=FALSE
  system("sed -i 's/XMR_EMACROSS_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/XMR_EMACROSS_COL/red/' ../index1.html")
}

message(paste("XMR EMA cross signal is",xmr_signal))
## XMR EMA cross signal is NONE
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="XMR EMA cross")
grid()
lines(price2$ma1~ as.Date(price2$date) ,col="red")
lines(price2$ma2~ as.Date(price2$date) ,col="blue")

XMR DMI indicator

Directional movement indicator is a good approach to identify trend changes.

n <- as.numeric(params[params$indicator == "DMI",2])

dmi.adx <- ADX(price[,c("high","low","close")],n=n)
price2 <- cbind(price,dmi.adx)
price2$signal <- dmi.adx[,1] > dmi.adx[,2]
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close DIp DIn DX ADX signal
2022-09-24 143.9085 140.7304 141.7651 17.66315 22.33587 11.682092 8.326711 FALSE
2022-09-25 144.5276 140.1472 141.1041 17.63814 22.17759 11.401161 8.373294 FALSE
2022-09-26 146.1058 139.9758 145.7094 17.71896 21.95651 10.680525 8.408252 FALSE
2022-09-27 152.8920 143.1812 144.6130 18.54223 21.60998 7.640315 8.396616 FALSE
2022-09-28 147.9419 140.3032 147.2961 18.31140 21.80999 8.720005 8.401516 FALSE
2022-09-29 149.1473 146.7070 147.5753 18.43643 21.72227 8.182149 8.398192 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    xmr_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    xmr_signal="SELL"
  }
} else {
  xmr_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_DMI=TRUE
  system("sed -i 's/XMR_DMI_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/XMR_DMI_COL/limegreen/' ../index1.html")
} else {
  ens_DMI=FALSE
  system("sed -i 's/XMR_DMI_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/XMR_DMI_COL/red/' ../index1.html")
}

message(paste("XMR DMI signal:",xmr_signal))
## XMR DMI signal: NONE
price2 <- as.data.frame(price2)
par(mfrow=c(2,1))
plot(price2$close~as.Date(price2$date),type="l",
  xlab="Date",ylab="price (USD)",main="XMR USD price")
grid()
plot(price2$DIp~as.Date(price2$date),type="l", col="blue",
  xlab="Date",ylab="price (USD)",main="XMR DMI")
grid()
lines(price2$DIn ~ as.Date(price2$date) ,col="red")

XMR TSI indicator

Probably the best performing indicator across most price series data.

n <- as.numeric(unlist(strsplit(params[params$indicator == "TSI",2],",")))
n1 <- n[1]
n2 <- n[2]
ns <- n[3]

TSI <- function(x, n.first = 25, n.second = 13, n.signal = 7) {
  #True Strength Indicator
  #https://school.stockcharts.com/doku.php?id=technical_indicators:true_strength_index
  x <- try.xts(x, error = as.matrix)
  pc <- x - lag.xts(x, na.pad = T) #force lag.xts to get na padding
  dspc <- EMA(EMA(pc, n = n.first), n = n.second)
  dsapc <- EMA(EMA(abs(pc), n = n.first), n = n.second)

  tsi <- 100 * (dspc/dsapc)
  signal <- EMA(tsi, n = n.signal)
  r <- cbind(tsi, signal)
  r <- reclass(r, x)
  if (!is.null(dim(r))) colnames(r) <- c("tsi", "signal")
  return(r)
}

tsi <- TSI(price$close , n.first = n1, n.second = n2, n.signal = ns )
colnames(tsi) <- c("tsi","sig")

price2 <- cbind(price,tsi)
price2$signal <- tsi[,1] > tsi[,2]
tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close tsi sig signal
2022-09-24 143.9085 140.7304 141.7651 -3.392380 -3.052215 FALSE
2022-09-25 144.5276 140.1472 141.1041 -3.579238 -3.263025 FALSE
2022-09-26 146.1058 139.9758 145.7094 -3.546762 -3.376520 FALSE
2022-09-27 152.8920 143.1812 144.6130 -3.562248 -3.450811 FALSE
2022-09-28 147.9419 140.3032 147.2961 -3.457844 -3.453624 FALSE
2022-09-29 149.1473 146.7070 147.5753 -3.350880 -3.412526 TRUE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    xmr_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    xmr_signal="SELL"
  }
} else {
  xmr_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_TSI=TRUE
  system("sed -i 's/XMR_TSI_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/XMR_TSI_COL/limegreen/' ../index1.html")
} else {
  ens_TSI=FALSE
  system("sed -i 's/XMR_TSI_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/XMR_TSI_COL/red/' ../index1.html")
}

message(paste("XMR TSI signal:",xmr_signal))
## XMR TSI signal: BUY
par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(tsi[,1] ~ as.Date(price2$date),type="l",col="blue",
  xlab="Date",ylab="TSI",main="TSI")
lines(as.Date(price2$date), tsi[,2]  , col="red"  )
grid()

par(mfrow=c(1,1))

XMR stochastic oscillator indicator

n <- as.numeric(unlist(strsplit(params[params$indicator == "stoch",2],",")))
n1 <- n[1]
n2 <- n[2]
n3 <- n[3]

sto <- stoch(HLC(price), nFastK=n1 , nFastD=n2 , nSlowD=n2 , bounded = TRUE, smooth=n3)

price2 <- cbind(price,sto)
price2$signal <- price2$fastK > price2$fastD

tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close fastK fastD slowD signal
2022-09-24 143.9085 140.7304 141.7651 0.2047479 0.5318638 0.6157778 FALSE
2022-09-25 144.5276 140.1472 141.1041 0.2143011 0.5207693 0.6153552 FALSE
2022-09-26 146.1058 139.9758 145.7094 0.2384226 0.5099432 0.6147129 FALSE
2022-09-27 152.8920 143.1812 144.6130 0.2894465 0.4998074 0.6138688 FALSE
2022-09-28 147.9419 140.3032 147.2961 0.3061969 0.4904259 0.6128416 FALSE
2022-09-29 149.1473 146.7070 147.5753 0.3392374 0.4817052 0.6116438 FALSE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    xmr_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    xmr_signal="SELL"
  }
} else {
  xmr_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_stoch=TRUE
  system("sed -i 's/XMR_STOCH_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/XMR_STOCH_COL/limegreen/' ../index1.html")
} else {
  ens_stoch=FALSE
  system("sed -i 's/XMR_STOCH_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/XMR_STOCH_COL/red/' ../index1.html")
}

message(paste("XMR stoch signal:",xmr_signal))
## XMR stoch signal: NONE
par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(price2$fastK ~ as.Date(price2$date),type="l",col="blue",
  xlab="Date",ylab="index",main="stochastic oscillator")
lines(as.Date(price2$date), price2$fastD  , col="red"  )
grid()

par(mfrow=c(1,1))

XMR double RSI indicator

n <- as.numeric(unlist(strsplit(params[params$indicator == "RSI2",2],",")))
n1 <- n[1]
n2 <- n[2]

rsi1 <- RSI(price$close,n=n1,maType=EMA)
rsi2 <- RSI(price$close,n=n2,maType=EMA)

price2 <- cbind(price,rsi1,rsi2)
price2$signal <- price2$rsi1 > price2$rsi2

tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close rsi1 rsi2 signal
2022-09-24 143.9085 140.7304 141.7651 44.97797 47.38342 FALSE
2022-09-25 144.5276 140.1472 141.1041 44.53856 47.23518 FALSE
2022-09-26 146.1058 139.9758 145.7094 48.28575 48.38581 FALSE
2022-09-27 152.8920 143.1812 144.6130 47.47291 48.13027 FALSE
2022-09-28 147.9419 140.3032 147.2961 49.67966 48.80695 TRUE
2022-09-29 149.1473 146.7070 147.5753 49.91279 48.87794 TRUE
today_signal <- price2[nrow(price2),"signal"]
previous_signal <- price2[(nrow(price2)-1),"signal"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    xmr_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    xmr_signal="SELL"
  }
} else {
  xmr_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_RSI2=TRUE
  system("sed -i 's/XMR_RSI_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/XMR_RSI_COL/limegreen/' ../index1.html")
} else {
  ens_RSI2=FALSE
  system("sed -i 's/XMR_RSI_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/XMR_RSI_COL/red/' ../index1.html")
}

message(paste("XMR RSI signal:",xmr_signal))
## XMR RSI signal: NONE
par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(price2$rsi1 ~ as.Date(price2$date),type="l",col="blue",
  xlab="Date",ylab="index",main="double RSI")
lines(as.Date(price2$date), price2$rsi2  , col="red"  )
grid()

par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(price2$rsi1/price2$rsi2 ~ as.Date(price2$date),type="l",
  xlab="Date",ylab="RSI ratio",main="double RSI")
grid()
abline(h=1,lty=2,lwd=2)

par(mfrow=c(1,1))

XMR Donchian channel indicator

n <- as.numeric(params[params$indicator == "DC",2])

price2 <- price[1:nrow(price)-1,]
dc <- DonchianChannel(price2$close,n=n)

price2$higher <- c(NA,sapply(2:nrow(dc),function(i) {
  dc[i,"high"] > dc[(i-1),"high"]
} ))
price2$lower <- c(NA,sapply(2:nrow(dc),function(i) {
  dc[i,"low"] < dc[(i-1),"low"]
} ))
price2 <- price2[price2$higher != price2$lower,]
# show changing rows only
price2 <- price2[c(NA,unlist(lapply(2:nrow(price2) , function(i) {
  price2$higher[i] != price2$higher[i-1]
}))),]
price2 <- price2[!is.na(price2$higher),]

previous_signal <- price2[nrow(price2),"higher"]

price2 <- price
dc <- DonchianChannel(price2$close,n=n)
colnames(dc) <- c("dchigh","dcmid","dclow")
price2 <- cbind(price2,dc)

tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close dchigh dcmid dclow
2022-09-24 143.9085 140.7304 141.7651 163.9119 149.7593 135.6067
2022-09-25 144.5276 140.1472 141.1041 163.9119 149.7593 135.6067
2022-09-26 146.1058 139.9758 145.7094 163.9119 149.7593 135.6067
2022-09-27 152.8920 143.1812 144.6130 163.9119 149.7593 135.6067
2022-09-28 147.9419 140.3032 147.2961 163.9119 149.7593 135.6067
2022-09-29 149.1473 146.7070 147.5753 163.9119 149.7593 135.6067
xmr_signal="NONE"

# if we in negative territory, check whether time to buy
if ( previous_signal == FALSE ) {
  if ( price2[nrow(price2),"dchigh"] > price2[nrow(price2)-1,"dchigh"] ) {
    xmr_signal="BUY"
  }
}

# if we in positive territory, check whether time to sell
if ( previous_signal == TRUE ) {
  if ( price2[nrow(price2),"dclow"] < price2[nrow(price2)-1,"dclow"] ) {
    xmr_signal="SELL"
  }
}

if ( xmr_signal=="NONE" ) {
  today_signal=previous_signal
} else {
  if (xmr_signal=="BUY") { today_signal = TRUE }
  if (xmr_signal=="SELL") { today_signal = FALSE }
}

if (today_signal==TRUE) {
  ens_DC=TRUE
  system("sed -i 's/XMR_DC_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/XMR_DC_COL/limegreen/' ../index1.html")
} else {
  ens_DC=FALSE
  system("sed -i 's/XMR_DC_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/XMR_DC_COL/red/' ../index1.html")
}

message(paste("XMR DC signal:",xmr_signal))
## XMR DC signal: NONE
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price",lwd=2)
grid()

lines(price2$dclow~ as.Date(price2$date),lwd=1.5,col="red")
lines(price2$dchigh~ as.Date(price2$date),lwd=1.5,col="limegreen")

price2 <- tail(price2,100)

plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price",lwd=2)
grid()

lines(price2$dclow~ as.Date(price2$date),lwd=1.5,col="red")
lines(price2$dcmid~ as.Date(price2$date),lwd=1.5,col="gray")
lines(price2$dchigh~ as.Date(price2$date),lwd=1.5,col="limegreen")

XMR KST indicator

Another high-performing indicator across different price series data.

price2 <- price

n <- as.numeric(unlist(strsplit(params[params$indicator == "KST",2],",")))
nScale <- n[1]
nrocScale <- n[2]
nSigs <- n[3]

kst <- KST(price2$close,n=nScale * c(10, 10, 10, 15) ,
  nROC=nrocScale * c(10, 15, 20, 30),
  nSig=nSigs)

price2 <- cbind(price2,kst)
price2$KST <- as.numeric(kst[,1]>kst[,2])

tail(price2) %>% kbl(row.names = FALSE) %>%  kable_styling("hover", full_width = F)
date high low close kst signal KST
2022-09-24 143.9085 140.7304 141.7651 -23.477129 -3.511337 0
2022-09-25 144.5276 140.1472 141.1041 -19.273361 -4.365961 0
2022-09-26 146.1058 139.9758 145.7094 -13.152069 -5.037067 0
2022-09-27 152.8920 143.1812 144.6130 -9.681649 -5.472140 0
2022-09-28 147.9419 140.3032 147.2961 -8.171095 -5.892443 0
2022-09-29 149.1473 146.7070 147.5753 -8.423658 -6.314720 0
today_signal <- price2[nrow(price2),"KST"]
previous_signal <- price2[(nrow(price2)-1),"KST"]
if (today_signal != previous_signal ) {
  if ( (today_signal == TRUE ) & (previous_signal == FALSE ) ) {
    xmr_signal="BUY"
  }
  if ( (today_signal == FALSE ) & (previous_signal == TRUE ) ) {
    xmr_signal="SELL"
  }
} else {
  xmr_signal <- "NONE"
}

if (today_signal==TRUE) {
  ens_KST=TRUE
  system("sed -i 's/XMR_KST_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/XMR_KST_COL/limegreen/' ../index1.html")
} else {
  ens_KST=FALSE
  system("sed -i 's/XMR_KST_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/XMR_KST_COL/red/' ../index1.html")
}

message(paste("XMR KST signal:",xmr_signal))
## XMR KST signal: NONE
par(mfrow=c(2,1))
plot(price2$close ~ as.Date(price2$date),type="l",log="y",
  xlab="Date",ylab="price (USD)",main="USD price")
grid()

plot(kst[,1] ~ as.Date(price2$date),type="l",col="blue",
  xlab="Date",ylab="KST",main="KST")
lines(as.Date(price2$date), kst[,2]  , col="red"  )
grid()

par(mfrow=c(1,1))

XMR Ensemble indicator

This is a combination of a number of n=y indicators, where x/y are a buy/sell threshold.

ens <- params[params$indicator=="Ensemble","parameter"]
myrev <- intToUtf8(rev(utf8ToInt(ens)))
myrev <- unlist(strsplit(myrev,","))
# get thresh
n <- as.numeric(myrev[1])
myrev <- myrev[2:length(myrev)]
# get combination
combo <- sapply(myrev,function(s) { intToUtf8(rev(utf8ToInt(s))) })

message(paste("The combination is",paste(combo,collapse=" ")))
## The combination is KST DC RSI2 stoch TSI EMAcross
message(paste("The buy threshold is",n))
## The buy threshold is 3
indicators <- c("SMA"=ens_SMA,
  "EMA"=ens_EMA,
  "SMAcross"=ens_SMAcross,
  "EMAcross"=ens_EMAcross,
  "DMI"=ens_DMI,
  "TSI"=ens_TSI,
  "stoch"=ens_stoch,
  "RSI2"=ens_RSI2,
  "DC"=ens_DC,
  "KST"=ens_KST)

indicators <- indicators[names(indicators) %in% combo]
message("State of the indicators:")
## State of the indicators:
indicators
## EMAcross      TSI    stoch     RSI2       DC      KST 
##    FALSE     TRUE    FALSE     TRUE    FALSE    FALSE
today_count <- sum(indicators)
message(paste("today_count_XMR",today_count,sep="="))
## today_count_XMR=2
today_signal <- today_count>=n

prev_signal <- length(grep("XMR ensemble indicator is BULLISH",prev_html))>1

xmr_signal <- "NONE"

if ( today_signal != prev_signal ) {
  if ( today_signal == TRUE ) {
    xmr_signal="BUY"
  } else {
    xmr_signal="SELL"
  }
}

if (today_signal==TRUE) {
  system("sed -i 's/XMR_ENS_DAILY/BULLISH/' ../index1.html")
  system("sed -i 's/XMR_ENS_COL/limegreen/' ../index1.html")
  message("XMR ensemble indicator is BULLISH")
} else {
  system("sed -i 's/XMR_ENS_DAILY/BEARISH/' ../index1.html")
  system("sed -i 's/XMR_ENS_COL/red/' ../index1.html")
  message("XMR ensemble indicator is BEARISH")
}
## XMR ensemble indicator is BEARISH
message(paste("XMR ENS signal:",xmr_signal))
## XMR ENS signal: SELL

Session information

For reproducibility


Click HERE to show session info

sessionInfo()
## R version 4.1.2 (2021-11-01)
## Platform: aarch64-unknown-linux-gnu (64-bit)
## Running under: Ubuntu 22.04.1 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/aarch64-linux-gnu/blas/libblas.so.3.10.0
## LAPACK: /usr/lib/aarch64-linux-gnu/lapack/liblapack.so.3.10.0
## 
## locale:
##  [1] LC_CTYPE=en_AU.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_AU.UTF-8        LC_COLLATE=en_AU.UTF-8    
##  [5] LC_MONETARY=en_AU.UTF-8    LC_MESSAGES=en_AU.UTF-8   
##  [7] LC_PAPER=en_AU.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_AU.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] kableExtra_1.3.4 quantmod_0.4.20  TTR_0.24.3       xts_0.12.1      
##  [5] zoo_1.8-10       runner_0.4.1     forcats_0.5.1    stringr_1.4.0   
##  [9] dplyr_1.0.9      purrr_0.3.4      readr_2.1.2      tidyr_1.2.0     
## [13] tibble_3.1.8     ggplot2_3.3.6    tidyverse_1.3.2  jsonlite_1.8.0  
## 
## loaded via a namespace (and not attached):
##  [1] httr_1.4.4          sass_0.4.2          viridisLite_0.4.0  
##  [4] modelr_0.1.8        bslib_0.4.0         assertthat_0.2.1   
##  [7] highr_0.9           googlesheets4_1.0.1 cellranger_1.1.0   
## [10] yaml_2.3.5          pillar_1.8.0        backports_1.4.1    
## [13] lattice_0.20-45     glue_1.6.2          digest_0.6.29      
## [16] rvest_1.0.2         colorspace_2.0-3    htmltools_0.5.3    
## [19] pkgconfig_2.0.3     broom_1.0.0         haven_2.5.0        
## [22] bookdown_0.28       scales_1.2.0        webshot_0.5.3      
## [25] svglite_2.1.0       tzdb_0.3.0          googledrive_2.0.0  
## [28] generics_0.1.3      ellipsis_0.3.2      cachem_1.0.6       
## [31] withr_2.5.0         cli_3.3.0           magrittr_2.0.3     
## [34] crayon_1.5.1        readxl_1.4.1        evaluate_0.16      
## [37] fs_1.5.2            fansi_1.0.3         xml2_1.3.3         
## [40] tools_4.1.2         hms_1.1.1           gargle_1.2.0       
## [43] lifecycle_1.0.1     munsell_0.5.0       reprex_2.0.2       
## [46] compiler_4.1.2      jquerylib_0.1.4     systemfonts_1.0.4  
## [49] rlang_1.0.4         grid_4.1.2          rstudioapi_0.13    
## [52] rmarkdown_2.15      gtable_0.3.0        DBI_1.1.3          
## [55] curl_4.3.2          R6_2.5.1            lubridate_1.8.0    
## [58] knitr_1.39          fastmap_1.1.0       utf8_1.2.2         
## [61] stringi_1.7.8       parallel_4.1.2      rmdformats_1.0.4   
## [64] Rcpp_1.0.9          vctrs_0.4.1         dbplyr_2.2.1       
## [67] tidyselect_1.1.2    xfun_0.32